from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
from HomVec3 import *
from OpenGL.arrays import vbo
from numpy import array
import sys, math, os

boundingBox = {'x':None,'-x':None,'y':None,'-y':None,'z':None,'-z':None}
scale = None
points=None
xAngle,yAngle,zAngle=0,0,0
animateX = False
animateY = False
animateZ = False

EXIT = -1
FIRST = 0

def init(width, height):
    
   global points,mid,scale
   points=readPoints("bunny_points.raw")
   scale=getScale()
   mid = getMid()
   print scale
   """ Initialize an OpenGL window """
   glClearColor(0.0, 0.0, 0.0, 0.0)         #background color
   glEnable(GL_DEPTH_TEST)
   glMatrixMode(GL_PROJECTION)              #switch to projection matrix
   glLoadIdentity()                         #set to 1
   gluPerspective(45.,float(width)/height,0.1,100.0)
   glOrtho(-1.5, 1.5, -1.5, 1.5, -1.0, 1.0) #multiply with new p-matrix
   
   glMatrixMode(GL_MODELVIEW)               #switch to modelview matrix
   
   
def readPoints(fname):
  l=[]
  for line in open(fname):
    x,y,z=map(float,line.split())
    actBBox({"x":x,"y":y,"z":z})
    l.append([x,y,z])
        
  print "Punkte eingelesen --> Boundingbox erstellt"
  return l

def getMid():
  global mid,boundingBox    
  p = HomVec3(boundingBox['-x'],boundingBox['-y'],boundingBox['-z'],1)
  q = HomVec3(boundingBox['x'],boundingBox['y'],boundingBox['z'],1)
  mid = (p+q) / 2
  
  return mid

def getScale():
  return 2.0 / max(abs(boundingBox['x']-boundingBox['-x']),
  abs(boundingBox['y']-boundingBox['-y']),abs(boundingBox['z']-boundingBox['-z']))
    

def actBBox(param):
    global boundingBox
    for ele in param.keys():
        if boundingBox['-%s'%ele] > param[ele] or not boundingBox['-%s'%ele]:
            boundingBox['-%s'%ele]=param[ele]
        if boundingBox['%s'%ele] < param[ele] or not boundingBox['%s'%ele]:
            boundingBox['%s'%ele]=param[ele]
  
def display():
   global points,scale,xAngle,yAngle,zAngle,mid
   """ Render all objects"""
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
   glColor3f(0.0, 0.0, 1.0)       #render stuff
   
   glLoadIdentity() 
   
   #Rotate around y-Axis
   
   glRotate(yAngle,0.0,1,0)
   glRotate(xAngle,1,0,0)
   glRotate(zAngle,0,0,1)
   glScale(scale,scale,scale)
   glTranslate(-mid.x,-mid.y,-mid.z)
   
   printVBO(points)
   glutSwapBuffers()            #swap buffer
   

def printVBO(points):
  vb = vbo.VBO(array(points,'f'))
  vb.bind()
  glVertexPointerf(vb)
  glEnableClientState(GL_VERTEX_ARRAY)
  glDrawArrays(GL_POINTS,0,len(points))
  vb.unbind()
  glDisableClientState(GL_VERTEX_ARRAY)
  glFlush()

def reshape(width, height):
   """ adjust projection matrix to window size"""
   glViewport(0, 0, width, height)
   glMatrixMode(GL_PROJECTION)
   glLoadIdentity()
   if width <= height:
       glOrtho(-1.5, 1.5,
               -1.5*height/width, 1.5*height/width,
               -1.0, 1.0)
   else:
       glOrtho(-1.5*width/height, 1.5*width/height,
               -1.5, 1.5,
               -1.0, 1.0)
   glMatrixMode(GL_MODELVIEW)


def keyPressed(key, x, y):
   global animateX,animateY,animateZ
   """ handle keypress events """
   if key == chr(27): # chr(27) = ESCAPE
       sys.exit()
   if key == 'a':
     animateY=True
   if key == 'w':
     animateX=True
   if key == 'e':
     animateZ=True
   glutPostRedisplay()
   
def animation():
  global xAngle,yAngle,zAngle,animateY,animateZ,animateX
  if animateY:
    yAngle = (yAngle + 0.0001) % 360
    print "Y"
  if animateZ:
    zAngle=(zAngle + 0.0001) % 360
    print "Z"
  if animateX:
    xAngle=(xAngle + 0.0001) % 360
  

def mouse(button, state, x, y):
   """ handle mouse events """
   if button == GLUT_LEFT_BUTTON and state == GLUT_DOWN:
       print "left mouse button pressed at ", x, y

def mouseMotion(x,y):
   """ handle mouse motion """
   print "mouse motion at ", x, y


def menu_func(value):
   """ handle menue selection """
   print "menue entry ", value, "choosen..."
   if value == EXIT:
       sys.exit()
   glutPostRedisplay()

def main():
   # Hack for Mac OS X
   cwd = os.getcwd()
   glutInit(sys.argv)
   os.chdir(cwd)

   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
   glutInitWindowSize(500, 500)
   glutCreateWindow("PointCloudView")

   glutDisplayFunc(display)     #register display function
   glutReshapeFunc(reshape)     #register reshape function
   glutKeyboardFunc(keyPressed) #register keyboard function 
   glutMouseFunc(mouse)         #register mouse function
   glutMotionFunc(mouseMotion)  #register motion function
   glutCreateMenu(menu_func)    #register menue function
   #Register Idle Callback
   glutIdleFunc(animation)

   glutAddMenuEntry("First Entry",FIRST) #Add a menu entry
   glutAddMenuEntry("EXIT",EXIT)         #Add another menu entry
   glutAttachMenu(GLUT_RIGHT_BUTTON)     #Attach mouse button to menue

   init(500,500) #initialize OpenGL state

   glutMainLoop() #start even processing


if __name__ == "__main__":
   main()